package mainServer;


import interaction.BDConnection;
import interaction.BDDisconnect;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.SocketTimeoutException;

import utils.StreamUtils;

public class UdpServer extends DefaultServer
{
  private static final int BUFFER_SIZE = 10000;    
  private static final int TIMEOUT = 1000;
  private int m_port;
  private boolean m_isActive = false;
  private Listener m_listener = new Listener();  
  DatagramSocket m_socket;  
  
  public UdpServer(int port)
  {
    m_port = port;    
  }
  
  private class Listener implements Runnable
  {     
    private DatagramPacket m_packet;
    
    @Override
    public void run()
    {
      while(m_isActive)
      {
        try
        {         
          m_packet = new DatagramPacket(new byte[BUFFER_SIZE], BUFFER_SIZE);
          m_socket.receive(m_packet);
          System.out.println("Принят пакет от " + m_packet.getAddress().toString());
          
          Object obj = StreamUtils.getDatagramObject(m_packet);
          
          if(obj != null)    
          {          
            if(obj instanceof BDConnection)
            {
              Integer id = addClient((BDConnection)obj);
              
              ((BDConnection)obj).m_clientId = id;
              sendConnection((BDConnection)obj);
            }
            else if(obj instanceof BDDisconnect)
              removeClient((BDDisconnect)obj);
            else
              System.out.println("Передана необрабатываемая логика");
          }
          else
            m_isActive = false;
        }
        catch (SocketTimeoutException e)
        {
          if(m_isActive == true)
          {
           // System.out.println("Нет запросов от клиентов в течение 1 секунды");
          }
        }
        catch (IOException e)
        {
          m_isActive = false;
          System.out.println("Ошибка принятия данных из UDP сокета");
        }       
      }
      
      m_socket.close();
    }
    
    private void sendConnection(BDConnection quaryConn)
    {      
      if(StreamUtils.fillDatagramPacket(m_packet, m_port, null, quaryConn) == true)
      {
        try
        {
          m_socket.send(m_packet);
        }
        catch (IOException e)
        {
          System.out.println("Ошибка передачи данных клиенту");
        }
        
        System.out.println("Передан ответ на соединение " + m_packet.getAddress().toString());
      }
    }
    
}
  
  @Override
  public boolean start()
  {
    if(m_isActive == true)
    {
      System.out.println("Попытка повторного создания UDP сокета");
      return true;
    }
    
    try
    {
      m_socket = new DatagramSocket(m_port);
    }
    catch (SocketException e)
    {   
      System.out.println("Ошибка создания UDP сокета, порт занят");      
      return false;      
    }
    
    Thread listener = new Thread(m_listener);
    
    try
    {
      m_socket.setSoTimeout(TIMEOUT);
    }
    catch (SocketException e)
    {            
      System.out.println("Ошибка установки таймаута");
      return false;
    }
    
    listener.start();
    m_isActive = true;
    System.out.println("Создан UDP сокет");
    
    return true;
  }

  @Override
  public boolean stop()
  {
    if(m_isActive == false)
    {
      System.out.println("Попытка остановки неинициализированного UDP сокета");
      return true;
    }    
    
    m_isActive = false;
    
    return true;
  }
}
